const logger = require("../common/log").logger("index");
const request = require('request');
const fs = require('fs');
const md5 = require('md5');
const path = require('path');


function ranStr(len) {
    let key = "";
    const ascTable = ["0", "1", "2", "3", "4", "5",
        "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h",
        "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
        "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H",
        "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
        "U", "V", "W", "X", "Y", "Z"];
    for (let i = 0; i < len; ++i) {
        key += ascTable[parseInt(Math.random() * 62)].toString();
    }
    return key.toUpperCase();
}

function randomDeviceId() {
    return ranStr(8) + '-' + ranStr(4) + '-' + ranStr(4) + '-' + ranStr(4) + '-' + ranStr(12)
}

function randomFileId(uri) {
    const fileObj = path.parse(uri);
    return fileObj.name + '_' + md5(ranStr(10) + (+new Date)) + fileObj.ext
}

function downloadImg(url) {
    const fileId = randomFileId(url);
    const filepath = path.join(__dirname, '../uploads/' + fileId);
    return new Promise((resolve, reject) => {
        request.get({
            url: url,
            encoding: 'binary'
        }, (err, res, body) => {
            if (err) {
                return reject(err);
            }
            try {
                fs.writeFileSync(filepath, body, {
                    encoding: 'binary'
                });
            } catch (e) {
                return reject(e);
            }
            resolve(filepath);
        });
    });
}

function formatImg(file) {
    const fileId = randomFileId(file.originalname);
    const filepath = path.join(__dirname, '../uploads/' + fileId);
    return new Promise((resolve, reject) => {
        fs.writeFile(filepath, file.buffer, err => {
            if (err) {
                return reject(err);
            }
            resolve(filepath);
        });
    });
}

function upload(filepath) {
    const deviceId = randomDeviceId();
    return new Promise((resolve, reject) => {
        request.post({
            url: 'https://api.mathpix.com/json',
            formData: {
                file: fs.createReadStream(filepath)
            },
            timeout: 2 * 60 * 1000,
            headers: {
                'Host': 'api.mathpix.com',
                'Content-Type': 'multipart/form-data;',
                //'DeviceId': '2E221FA4-2031-4F65-B487-2FB176CD5D28',
                'DeviceId': deviceId,
                'Connection': 'keep-alive',
                'Accept': '*/*',
                'Accept-Language': 'zh-cn'
                // 'User-Agent': 'Mathpix/3.4.1 CFNetwork/808.3 Darwin/16.3.0'
            }
        }, (err, httpResponse, body) => {
            if (err) {
                return reject(err);
            }
            fs.unlink(filepath, () => {
            });
            resolve({
                httpResponse: httpResponse,
                body: body
            });
        })
    });
}

exports.upload = upload;
exports.identify = async(req, res) => {
    const method = req.method.toLowerCase();
    const url = req.query.url;
    if (method === 'get' && !url) {
        return res.json({
            desc: 'wrong image url',
            status: 10002
        });
    }
    let fun = method === 'get' ? downloadImg : formatImg;
    let filepath = '';
    try {
        filepath = await fun(method === 'get' ? decodeURIComponent(url) : req.file);
    } catch (e) {
        logger.error(e);
        return res.json({
            desc: 'image format error',
            status: 10003
        });
    }
    let body = '';
    try {
        const resp = await upload(filepath);
        body = resp.body;
    } catch (e) {
        logger.error('request error', e);
        return res.json({
            desc: typeof e === 'object' ? JSON.stringify(e) : e,
            status: 10001
        });
    }
    let info = {};
    try {
        info = typeof body === 'object' ? body : JSON.parse(body);
    } catch (e) {
        if (e) {
            logger.error(e);
            return res.json({
                desc: body,
                status: 10003
            });
        }
    }
    logger.info(info);
    if (info.error) {
        logger.error(info.error);
        return res.json({
            desc: info.error,
            status: 10003
        });
    }
    res.json({
        status: 10000,
        desc: `${+new Date - req.start_time}ms`,
        data: info
    });
};